package org.homonoia.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.rmi.UnknownHostException;

import org.homonoia.model.query.Query;
import org.homonoia.model.query.QueryID;
import org.homonoia.model.query.QueryResults;
import org.homonoia.model.query.QueryStatus;

public class JobClient {

    private String hostname;
    private int port;

    /**
     * Constructor to create a JobClient and connect to the JobServer at the
     * specified hostname and port.
     * 
     * @param hostname
     *            hostname of the server e.g. 192.168.0.1
     * @param port
     *            port of the server e.g. 5060
     */
    public JobClient(final String hostname, final int port) {
	this.hostname = hostname;
	this.port = port;
    }

    /**
     * Function to submit a created Job to the JobServer and get the JobID that
     * has been assigned to the Job.
     * 
     * @param j
     *            Job to submit to be run
     * @return The JobID assigned to the newly created Job
     * @throws ClassNotFoundException
     */
    public QueryID submitQuery(final Query job) throws IOException, UnknownHostException,
	    ClassNotFoundException {
	Socket sock = null;
	PrintWriter out = null;
	BufferedReader in = null;
	ObjectInputStream ois = null;
	ObjectOutputStream oos = null;
	QueryID id = null;

	try {
	    sock = new Socket(hostname, port);
	    out = new PrintWriter(sock.getOutputStream(), true);
	    in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

	    out.println(createRequestHeader("submission"));
	    String response = in.readLine();

	    if (verifyResponse(response)) {
		oos = new ObjectOutputStream(sock.getOutputStream());
		oos.writeObject(job);

		ois = new ObjectInputStream(sock.getInputStream());
		id = (QueryID) ois.readObject();
	    }

	    return id;

	} finally {
	    if (sock != null) {
		sock.close();
	    }
	}
    }

    public final QueryStatus getStatus(final QueryID jobID) throws IOException,
	    UnknownHostException, ClassNotFoundException {
	Socket sock = null;
	PrintWriter out = null;
	BufferedReader in = null;
	ObjectInputStream ois = null;
	ObjectOutputStream oos = null;
	QueryStatus status = null;

	try {
	    sock = new Socket(hostname, port);
	    out = new PrintWriter(sock.getOutputStream(), true);
	    in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

	    out.println(createRequestHeader("status"));
	    String response = in.readLine();

	    if (verifyResponse(response)) {
		oos = new ObjectOutputStream(sock.getOutputStream());
		oos.writeObject(jobID);

		ois = new ObjectInputStream(sock.getInputStream());
		status = (QueryStatus) ois.readObject();

	    }

	    return status;

	} finally {
	    sock.close();
	}
    }

    public final QueryResults getResults(final QueryID jobID) throws IOException,
	    UnknownHostException, ClassNotFoundException {
	Socket sock = null;
	PrintWriter out = null;
	BufferedReader in = null;
	ObjectInputStream ois = null;
	ObjectOutputStream oos = null;
	QueryResults history = null;

	try {
	    sock = new Socket(hostname, port);
	    out = new PrintWriter(sock.getOutputStream(), true);
	    in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

	    out.println(createRequestHeader("results"));
	    String response = in.readLine();

	    if (verifyResponse(response)) {
		oos = new ObjectOutputStream(sock.getOutputStream());
		oos.writeObject(jobID);

		ois = new ObjectInputStream(sock.getInputStream());
		history = (QueryResults) ois.readObject();
	    }

	    return history;

	} finally {
	    sock.close();
	}
    }

    private final String createRequestHeader(final String reqType) {
	String header = "";
	header += "Request: application/" + reqType;

	return header;
    }

    private boolean verifyResponse(final String response) {
	if (response != null && response.contains("OK")) {
	    return true;
	}
	return false;
    }
}
